package com.UnionPayCenter.service.serviceImpl;

import com.UnionPayCenter.account.entity.Account;
import com.UnionPayCenter.account.entity.ChargeBill;
import com.UnionPayCenter.account.entity.FundsBill;
import com.UnionPayCenter.account.entity.dto.ChargeDTO;
import com.UnionPayCenter.account.entity.dto.FundsBillDTO;
import com.UnionPayCenter.account.enums.AccountTypeEnum;
import com.UnionPayCenter.account.enums.BillDutyEnum;
import com.UnionPayCenter.account.enums.ChargeStatusEnum;
import com.UnionPayCenter.account.enums.FundsBillTypeEnum;
import com.UnionPayCenter.account.enums.PayChannelEnum;
import com.UnionPayCenter.account.enums.PayStatusEnum;
import com.UnionPayCenter.account.manager.ChargeBillManager;
import com.UnionPayCenter.account.manager.PayBillManager;
import com.UnionPayCenter.account.service.AccountService;
import com.UnionPayCenter.account.service.ChargePayService;
import com.UnionPayCenter.account.service.FundsBillService;
import com.UnionPayCenter.constant.CouponConstants;
import com.UnionPayCenter.entity.GiveCouponEntity;
import com.UnionPayCenter.entity.UserEntity;
import com.UnionPayCenter.entity.UserLevelEntity;
import com.UnionPayCenter.entity.dto.ChargeResponse;
import com.UnionPayCenter.entity.dto.FundsPayDTO;
import com.UnionPayCenter.entity.dto.FundsQueryRequest;
import com.UnionPayCenter.entity.dto.TransferCouponsRequest;
import com.UnionPayCenter.entity.vo.CardInfoVo;
import com.UnionPayCenter.entity.vo.FundsBillRecordVo;
import com.UnionPayCenter.entity.vo.PageInfoExtender;
import com.UnionPayCenter.entity.vo.UserCouponVo;
import com.UnionPayCenter.entity.vo.UserVo;
import com.UnionPayCenter.enums.ErrorCodeEnum;
import com.UnionPayCenter.exception.ApiException;
import com.UnionPayCenter.mapper.GiveCouponMapper;
import com.UnionPayCenter.operation.entity.ActivityConfig;
import com.UnionPayCenter.operation.entity.request.MpPushRequest;
import com.UnionPayCenter.operation.enums.ActivityOperationTypeEnum;
import com.UnionPayCenter.operation.manager.ActivityConfigManager;
import com.UnionPayCenter.service.FundsAccountService;
import com.UnionPayCenter.service.ICouponService;
import com.UnionPayCenter.service.IShopService;
import com.UnionPayCenter.service.IUserLevelService;
import com.UnionPayCenter.service.IUserService;
import com.UnionPayCenter.service.IWechatService;
import com.UnionPayCenter.util.DateFormatUtil;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import static com.UnionPayCenter.enums.ErrorCodeEnum.TK2001;
import static com.UnionPayCenter.enums.ErrorCodeEnum.TK2002;
import static java.math.BigDecimal.valueOf;

/**
 * @author Noah
 * @since 1.0.0, 2019/05/19
 */
@Slf4j
@Service
public class FundsAccountServiceImpl implements FundsAccountService {


    @Autowired
    private AccountService accountService;

    @Autowired
    private ChargePayService chargePayService;

    @Autowired
    private ChargeBillManager chargeBillService;

    @Autowired
    private ICouponService couponService;

    @Autowired
    private IUserLevelService userLevelService;

    @Autowired
    private PayBillManager payBillService;

    @Autowired
    private IUserService userService;

    @Autowired
    private FundsBillService fundsBillService;

    @Autowired
    private IShopService shopService;

    @Autowired
    private IWechatService wechatService;

    @Autowired
    private ActivityConfigManager activityConfigManager;

    @Autowired
    private GiveCouponMapper giveCouponMapper;

    /**
     * 向某个用户ID进行充值
     *
     * @param strUserId
     * @param amount
     */
    @Override
    public JSONObject depositFundsAccount(String shopId, String strUserId, int amount, String openId) {
        Integer userId = Integer.valueOf(strUserId);
        Account account = getFirstAccountId(userId);
        ChargeDTO chargeDTO = new ChargeDTO();
        chargeDTO.setAccountId(account.getAccountId());
        chargeDTO.setShopId(Integer.valueOf(shopId));
        chargeDTO.setAmount(amount);
        chargeDTO.setTotalAmount(amount);
        chargeDTO.setOpenId(openId);
        chargeDTO.setPayChannel(PayChannelEnum.UNION_PAY);
        chargeDTO.setBillDuty(BillDutyEnum.CHARGE);
        ChargeResponse response = chargePayService.charge(chargeDTO);
        if (Objects.isNull(response)) {
            throw new ApiException(TK2002);
        }
//        MiniPayRequestVO requestVO = new MiniPayRequestVO();
//        try {
//            BeanUtils.copyProperties(response.getMiniPayRequest(), requestVO);
//            requestVO.setSn(response.getSn());
//        } catch (ApiException ex) {
//            log.error("属性复制出错");
//        }

        return wechatService.unionPay(Integer.valueOf(userId), Integer.valueOf(shopId), chargeDTO.getAmount(), response.getSn());
    }


    /**
     * 向某个用户ID进行充值
     *
     * @param shopId
     * @param userId
     * @param sn
     * @param state
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void depositBackFundsAccount(String shopId, String userId, String sn, String state) {
        chargePayService.updateState(sn, ChargeStatusEnum.SUCCESS); //fixme 状态
        ChargeBill bill = chargeBillService.getBySn(sn, AccountTypeEnum.CHARGE);
        userLevelService.updateByRecharge(Integer.valueOf(userId), bill.getAmount() / 100D);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void balancePay(FundsPayDTO payDTO) {
        payDTO.setPayChannel(PayChannelEnum.BALANCE_PAY);
        if (!payPreCheck(payDTO)) {
            throw new ApiException(ErrorCodeEnum.ZF5000);
        }
        payDTO.setPayChannel(PayChannelEnum.BALANCE_PAY);
        pay(payDTO);
    }

    /**
     * 支付校验
     * 总额 - (1-折扣值)截取 == 实付值
     *
     * @param payDTO
     * @return
     */
    private boolean payPreCheck(FundsPayDTO payDTO) {
        Integer userId = payDTO.getUserId();
        UserVo userVo = userService.getUserInfo(userId);
        if (userVo == null) {
            throw new ApiException(ErrorCodeEnum.SW50);
        }

        if (userVo.getDiscount() == null) {
            userVo.setDiscount(10D);
            // 如果是微信支付, 仅线上店铺的初始会员折扣
        } else if (PayChannelEnum.WECHAT_PAY == payDTO.getPayChannel()) {
            UserLevelEntity userLevelEntity = shopService.getShopInitialMemberLevel(payDTO.getShopId());
            if (userLevelEntity != null) {
                userVo.setDiscount(userLevelEntity.getDiscount());
            }
        }

        // 优惠的金额
        BigDecimal reduceAmount = BigDecimal.ZERO;

        BigDecimal activityAmount = valueOf(payDTO.getActivityAmount());
        BigDecimal totalAmount = valueOf(payDTO.getTotalAmount());

        // 优先使用优惠券
        // 是否开启开启开关针对余额支付
        // 是否开启会员卡折扣
        Integer enableMemberCard = 1;
        // 是否开启优惠券使用活动
        Integer enableCoupon = 1;
        if (PayChannelEnum.BALANCE_PAY.equals(payDTO.getPayChannel())) {
            ActivityConfig activityConfig = activityConfigManager.getByShopId(payDTO.getShopId(), ActivityOperationTypeEnum.BALANCE_PAY);
            if (activityConfig != null) {
                enableMemberCard = activityConfig.getMemberCardDiscount();
                enableCoupon = activityConfig.getCoupon();
            }
        }
        if (payDTO.getDiscountId() == null) {
            if (enableMemberCard == null || enableMemberCard.equals(1)) {
                BigDecimal memberCardDiscount = valueOf(userVo.getDiscount()).divide(new BigDecimal(10)).setScale(2,
                        BigDecimal.ROUND_HALF_UP);
                if (null == memberCardDiscount) {
                    memberCardDiscount = BigDecimal.ONE;
                }
                BigDecimal shouldPayActivityAmount = activityAmount.multiply(memberCardDiscount).setScale(0,
                        RoundingMode.DOWN);
                reduceAmount = activityAmount.subtract(shouldPayActivityAmount);
            }
        } else {
            UserCouponVo userCouponVo = couponService.getUserCouponByDisId(userId, payDTO.getDiscountId());
            if (userCouponVo != null && userCouponVo.getDisNum() != null && (enableCoupon == null || enableCoupon.equals(1))) {
                String disType = userCouponVo.getDisType();
                BigDecimal couponDiscount = valueOf(userCouponVo.getDisNum()).setScale(2, BigDecimal.ROUND_HALF_UP);
                BigDecimal minAmount = null == userCouponVo.getMinAmount() ? BigDecimal.ZERO : new BigDecimal(userCouponVo.getMinAmount());
                BigDecimal maxAmount = null == userCouponVo.getMaxAmount() ? totalAmount : new BigDecimal(userCouponVo.getMaxAmount());
                reduceAmount = getCouponReduceAmount(totalAmount, activityAmount, couponDiscount, minAmount, maxAmount,
                        disType);
            }
        }
        BigDecimal actual = totalAmount.subtract(reduceAmount);
        if (actual.equals(BigDecimal.ZERO)) {
            actual = BigDecimal.ONE;
        }


        if (actual.compareTo(BigDecimal.ZERO) < 0) {
            throw new ApiException(ErrorCodeEnum.ZF5000);
        }
        if (actual.compareTo(BigDecimal.ONE) < 0 && actual.compareTo(BigDecimal.ZERO) >= 0) {
            actual = BigDecimal.ONE;
        }
        log.info(String.format("payPreCheck 传入金额：%s ，计算金额：%s", payDTO.getAmount(), actual));
        return valueOf(payDTO.getAmount())
                .setScale(2, BigDecimal.ROUND_HALF_UP)
                .equals(actual.setScale(2, BigDecimal.ROUND_HALF_UP));

    }


    /**
     * 计算优惠券折扣后实际支付金额
     *
     * @param totalAmount     支付总金额
     * @param activityAmount  支付金额中参与折扣的金额
     * @param couponDiscount  优惠券折扣值(如0.9 9折)/满减金额(单位为分)
     * @param couponThreshold 优惠券使用条件金额
     * @param maxAmount       最大限额
     * @param disType         优惠类型(00抵扣券，01折扣券)
     * @return 优惠金额数
     */
    private BigDecimal getCouponReduceAmount(BigDecimal totalAmount, BigDecimal activityAmount, BigDecimal couponDiscount,
                                             BigDecimal couponThreshold,
                                             BigDecimal maxAmount,
                                             String disType) {
        if (null == couponThreshold) {
            return BigDecimal.ZERO;
        }
        if (null == maxAmount) {
            maxAmount = activityAmount;
        }

        // 没有达到优惠券使用条件, 返回0
        if (totalAmount.compareTo(couponThreshold) < 0) {
            return BigDecimal.ZERO;
        }

        // 计算参与优惠的金额,优惠后还需要支付的金额
        BigDecimal shouldPayActivityAmount;
        if (disType.equals(CouponConstants.DISCOUNT_TYPE_REDUCE)) {
            //若抵扣券金额大于等于订单金额,支付金额为0.01元(即1分)
            if (activityAmount.compareTo(couponDiscount) <= 0) {
                shouldPayActivityAmount = BigDecimal.ZERO;
            } else {
                shouldPayActivityAmount = activityAmount.subtract(couponDiscount);
            }
        } else {
            shouldPayActivityAmount = activityAmount.multiply(couponDiscount).setScale(0, RoundingMode.DOWN);
        }

        // 优惠金额数
        BigDecimal reduceAmount = activityAmount.subtract(shouldPayActivityAmount);
        if (reduceAmount.compareTo(maxAmount) > 0) {
            return maxAmount;
        }
        return reduceAmount;
    }

    /**
     * 支付
     *
     * @param payDTO
     */
    private void pay(FundsPayDTO payDTO) {
        Integer userId = payDTO.getUserId();
        Long accountId = getFirstAccountId(userId).getAccountId();
        payDTO.setAccountId(accountId);
        payDTO.setUserId(userId);
        chargePayService.pay(payDTO);
        if (null != payDTO.getDiscountId()) {
            couponService.consumptionCoupon(Integer.valueOf(userId), String.valueOf(payDTO.getDiscountId()));
        }
        userLevelService.updateByRecharge(Integer.valueOf(userId), payDTO.getAmount() / 100D);
    }

    /**
     * 向某个用户ID进行充值
     *
     * @param shopId
     * @param userId
     * @param amount
     * @param openId
     */
    @Override
    public JSONObject wechatDepositFundsAccount(String shopId, String userId, int amount, String openId) {
        Long accountId = getFirstAccountId(Integer.valueOf(userId)).getAccountId();
        ChargeDTO dto = new ChargeDTO();
        dto.setAccountId(accountId);
        dto.setAmount(amount);
        dto.setTotalAmount(amount);
        dto.setOpenId(openId);
        dto.setShopId(Integer.valueOf(shopId));
        dto.setPayChannel(PayChannelEnum.WECHAT_PAY);
        dto.setBillDuty(BillDutyEnum.CHARGE);
        ChargeResponse orderResponse = chargePayService.charge(dto);
        if (null == orderResponse) {
            throw new ApiException(ErrorCodeEnum.SC1);
        }

        return wechatService.pay(Integer.valueOf(userId), Integer.valueOf(shopId), orderResponse.getAmount(), orderResponse.getSn());

    }

    @Override
    public JSONObject wechatPay(FundsPayDTO payDTO) {
        Integer userId = payDTO.getUserId();
        if (!payPreCheck(payDTO)) {
            throw new ApiException(ErrorCodeEnum.ZF5000);
        }
        Long accountId = getFirstAccountId(userId).getAccountId();
        ChargeDTO dto = new ChargeDTO();
        BeanUtils.copyProperties(payDTO, dto);
        dto.setAccountId(accountId);
        dto.setPayChannel(PayChannelEnum.WECHAT_PAY);
        dto.setBillDuty(BillDutyEnum.CHARGE_AND_PAY);
        ChargeResponse orderResponse = chargePayService.charge(dto);
        if (null == orderResponse) {
            throw new ApiException(ErrorCodeEnum.SC1);
        }

        //微信支付
        return wechatService.pay(Integer.valueOf(userId), payDTO.getShopId(), payDTO.getAmount(), orderResponse.getSn());
    }

    @Override
    public JSONObject unionPay(FundsPayDTO payDTO) {
        Integer userId = payDTO.getUserId();
        if (!payPreCheck(payDTO)) {
            throw new ApiException(ErrorCodeEnum.ZF5000);
        }
        Long accountId = getFirstAccountId(userId).getAccountId();
        ChargeDTO dto = new ChargeDTO();
        BeanUtils.copyProperties(payDTO, dto);
        dto.setAccountId(accountId);
        dto.setPayChannel(PayChannelEnum.UNION_PAY);
        dto.setBillDuty(BillDutyEnum.CHARGE_AND_PAY);
        ChargeResponse orderResponse = chargePayService.charge(dto);
        if (null == orderResponse) {
            throw new ApiException(ErrorCodeEnum.SC1);
        }

        //银联支付
        return wechatService.unionPay(Integer.valueOf(userId), payDTO.getShopId(), payDTO.getAmount(), orderResponse.getSn());
    }

    /**
     * 微信支付回调处理服务类
     * 1:修改充值状态
     * 2:增加消费记录
     * 3:升级会员
     *
     * @param serialNumber
     * @param payStatusEnum
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer wechatPayBack(String serialNumber, PayStatusEnum payStatusEnum) {
        log.info("处理微信充值/支付回调信息开始-------------{}", serialNumber);
        ChargeBill chargeBill = getChargeBillByThirdSn(serialNumber);
        if (null == chargeBill) {
            log.error("根据流水号{}获取不到充值信息", serialNumber);
            return null;
        }

        if (PayStatusEnum.SUCCESS.equals(payStatusEnum)) {
            chargePayService.updateState(chargeBill.getSn(), ChargeStatusEnum.SUCCESS);
            //修改优惠券至使用
            if (null != chargeBill.getDiscountId()) {
                couponService.consumptionCoupon(chargeBill.getUserId(), String.valueOf(chargeBill.getDiscountId()));
            }
            if (BillDutyEnum.CHARGE_AND_PAY.equals(chargeBill.getBillDuty())) {
                FundsPayDTO payDTO = new FundsPayDTO();
                payDTO.setTotalAmount(chargeBill.getTotalAmount());
                payDTO.setAmount(chargeBill.getAmount());
                payDTO.setAccountId(chargeBill.getAccountId());
                payDTO.setShopId(chargeBill.getShopId());
                payDTO.setSn(chargeBill.getSn());
                payDTO.setPayChannel(PayChannelEnum.WECHAT_PAY);
                payDTO.setBillDuty(chargeBill.getBillDuty());
                payDTO.setUserId(chargeBill.getUserId());
                pay(payDTO);
            } else {
                userLevelService.updateByRecharge(Integer.valueOf(chargeBill.getUserId().intValue()), chargeBill.getAmount() / 100D);
            }

        } else {
            chargePayService.updateState(chargeBill.getSn(), ChargeStatusEnum.FAIL);
        }
        log.info("处理微信充值/支付回调信息结束-------------{}", serialNumber);
        return chargeBill.getUserId();
    }

    private ChargeBill getChargeBillByThirdSn(String thirdSn) {
        ChargeBill chargeBill = new ChargeBill();
        chargeBill.setThirdSn(thirdSn);
        Page<ChargeBill> billPage = chargeBillService.getChargeBillByCondition(chargeBill, 1, 1);
        if (null == billPage || billPage.getTotal() == 0) {
            log.error("charge bill is not exist, thirdSn {}", thirdSn);
            return null;
        }
        return billPage.get(0);
    }

    /**
     * 用户支付
     *
     * @param payDTO
     * @param userId       用户id
     * @param reduceAmount
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void depositPayFundsAccount(FundsPayDTO payDTO, String userId, Integer reduceAmount) {
        payDTO.setUserId(Integer.valueOf(userId));
        payDTO.setReduceAmount(reduceAmount);
        depositBackFundsAccount(String.valueOf(payDTO.getShopId()), userId, payDTO.getSerialNnumber(), payDTO.getStatus());
        balancePay(payDTO);
    }


    /**
     * 根据用户Id查询充值记录
     *
     * @param userId   用户Id
     * @param page
     * @param pageSize @return 充值记录
     */
    @Override
    public PageInfo<FundsBillRecordVo> listAllBillByUserId(String userId, String shopId, Integer page, Integer pageSize, String type,
                                                           FundsQueryRequest request) {

        FundsBillDTO fundsBill = assembleFundsBillQueryCondition(userId, type, shopId, request);
        Page<FundsBill> bills = fundsBillService.getMpFundsBillByCondition(fundsBill, page, pageSize);
        Page<FundsBillRecordVo> recordVoPage = new Page<>();
        try {
            BeanUtils.copyProperties(bills, recordVoPage);
            if (null != recordVoPage) {
                for (int i = 0; i < bills.size(); i++) {
                    FundsBill bill = bills.get(i);
                    FundsBillRecordVo recordVo = new FundsBillRecordVo();
                    recordVo.setAccountAmount(null == bill.getBalance() ? 0 : bill.getBalance());
                    recordVo.setAmount(bill.getAmount());
                    recordVo.setCreateTime(DateFormatUtil.dateToString(bill.getCreateTime()));
                    recordVo.setRecordId(bill.getSn());
                    recordVo.setMobile(bill.getMobile());
                    recordVo.setType(bill.getBillType().code());
                    recordVo.setThirdId(bill.getThirdSn());
                    recordVo.setRemark(bill.getRemark());
                    recordVo.setStatus(null == bill.getState() ? ChargeStatusEnum.FAIL.code() : bill.getState().code());
                    recordVoPage.add(i, recordVo);
                }
            }
        } catch (ApiException e) {
            log.error("查询资金列表出错");
        }
        return new PageInfo<>(recordVoPage);
    }

    /**
     * 根据用户Id查询资金流水
     *
     * @param request
     * @return 充值记录
     */
    @Override
    public PageInfoExtender<FundsBillRecordVo> listDepositByUserId(FundsQueryRequest request) {
        ChargeBill chargeBill = new ChargeBill();
        if (null != request.getUserId()) {
            chargeBill.setUserId(Integer.valueOf(request.getUserId()));
        }
        if (null != request.getShopId()) {
            chargeBill.setShopId(Integer.valueOf(request.getShopId()));
        }
        chargeBill.setStartCreateTime(request.getStartTime());
        chargeBill.setEndCreateTime(request.getEndTime());
        // chargeBill.setBillDuty(BillDutyEnum.CHARGE);
        chargeBill.setBankType("third");
        chargeBill.setBillDuty(request.getType());
        Page<ChargeBill> bills = chargeBillService.getChargeBillByCondition(chargeBill, request.getPage(), request.getPageSize());
        Page<FundsBillRecordVo> recordVoPage = new Page<>();
        try {
            BeanUtils.copyProperties(bills, recordVoPage);
            if (null != recordVoPage) {
                for (int i = 0; i < bills.size(); i++) {
                    ChargeBill bill = bills.get(i);
                    FundsBillRecordVo recordVo = new FundsBillRecordVo();
                    recordVo.setAccountAmount(null == bill.getBalance() ? 0 : bill.getBalance());
                    recordVo.setAmount(bill.getAmount());
                    recordVo.setCreateTime(DateFormatUtil.dateToString(bill.getCreateTime()));
                    recordVo.setRecordId(bill.getSn());
                    recordVo.setMobile(bill.getMobile());
                    recordVo.setType(2);
                    recordVo.setThirdId(bill.getThirdSn());
                    recordVo.setRemark(bill.getRemark());
                    recordVo.setStatus(null == bill.getState() ? ChargeStatusEnum.FAIL.code() : bill.getState().code());
                    recordVoPage.add(i, recordVo);
                }
            }
        } catch (ApiException e) {
            log.error("查询充值列表出错");
        }
        PageInfoExtender pageInfoExtender = new PageInfoExtender<>(recordVoPage);
        if (request.isSumOrNot()) {
            pageInfoExtender.setSum(chargeBillService.sumAmount(chargeBill));
        }
        return pageInfoExtender;
    }


    @Override
    public PageInfo<FundsBillRecordVo> listDepositByUserIdFront(String userId, String shopId, Integer page, Integer pageSize, String type
            , FundsQueryRequest request) {
        ChargeBill chargeBill = new ChargeBill();
        if (null != userId) {
            chargeBill.setUserId(Integer.valueOf(userId));
        }
        if (null != shopId) {
            chargeBill.setShopId(Integer.valueOf(shopId));
        }
        chargeBill.setBillDuty(BillDutyEnum.CHARGE);
        Page<ChargeBill> bills = chargeBillService.getChargeBillByCondition(chargeBill, page, pageSize);
        Page<FundsBillRecordVo> recordVoPage = new Page<>();
        try {
            BeanUtils.copyProperties(bills, recordVoPage);
            if (null != recordVoPage) {
                for (int i = 0; i < bills.size(); i++) {
                    ChargeBill bill = bills.get(i);
                    FundsBillRecordVo recordVo = new FundsBillRecordVo();
                    recordVo.setAccountAmount(null == bill.getBalance() ? 0 : bill.getBalance());
                    recordVo.setAmount(bill.getAmount());
                    recordVo.setCreateTime(DateFormatUtil.dateToString(bill.getCreateTime()));
                    recordVo.setRecordId(bill.getSn());
                    recordVo.setMobile(bill.getMobile());
                    recordVo.setType(2);
                    recordVo.setThirdId(bill.getThirdSn());
                    recordVo.setRemark(bill.getRemark());
                    recordVo.setStatus(null == bill.getState() ? ChargeStatusEnum.FAIL.code() : bill.getState().code());
                    recordVoPage.add(i, recordVo);
                }
            }
        } catch (ApiException e) {
            log.error("查询充值列表出错");
        }
        return new PageInfo<>(recordVoPage);
    }

    /**
     * 根据用户Id查询充值记录
     *
     * @param userId  用户Id
     * @param shopId
     * @param type
     * @param request
     * @return 充值记录
     */
    @Override
    public List<FundsBill> listBillByUserId(String userId, String shopId, String type, FundsQueryRequest request) {

        FundsBillDTO fundsBill = assembleFundsBillQueryCondition(userId, type, shopId, request);
        Page<FundsBill> bills = fundsBillService.getFundsBillByCondition(fundsBill, 1, 10);
        if (CollectionUtils.isEmpty(bills)) {
            return Collections.emptyList();
        }
        return fundsBillService.getFundsBillByCondition(fundsBill, 1, (int) bills.getTotal());
    }

    private FundsBillDTO assembleFundsBillQueryCondition(String userId, String type, String shopId, FundsQueryRequest request) {
        FundsBillDTO fundsBill = new FundsBillDTO();
        if (null != userId) {
            fundsBill.setUserId(Integer.valueOf(userId));
        }
        fundsBill.setShopId(Integer.valueOf(shopId));
        if ("1".equals(type)) {
            fundsBill.setBillType(FundsBillTypeEnum.PAY);
            fundsBill.setPayChannel(PayChannelEnum.BALANCE_PAY);
        } else if ("2".equals(type)) {
            fundsBill.setBillType(FundsBillTypeEnum.CHARGE);
            fundsBill.setBillDuty(BillDutyEnum.CHARGE);
        }
        fundsBill.setStartTime(request.getStartTime());
        fundsBill.setEndTime(request.getEndTime());
        return fundsBill;
    }


    /**
     * 获取首选账户
     *
     * @param userId 用户ID
     * @return
     */
    private Account getFirstAccountId(Integer userId) {
        Account account = accountService.getAccountByUserId(userId, AccountTypeEnum.CHARGE);
        if (Objects.isNull(account) || Objects.isNull(account.getAccountId())) {
            throw new ApiException(TK2001);
        }
        return account;
    }

    /**
     * 根据用户Id查询优惠券信息
     *
     * @param jsonParam 查询条件
     * @return 充值记录
     */
    @Override
    public PageInfo<Map<String, Object>> listAllVoucherByUserId(JSONObject jsonParam) {
        PageInfo<UserCouponVo> pageInfo = couponService.getUserCouponList(jsonParam);
        List<UserCouponVo> list = pageInfo.getList();
        if (null == list) {
            list = Collections.emptyList();
        }
        PageInfo<Map<String, Object>> result = new PageInfo<>();
        try {
            BeanUtils.copyProperties(pageInfo, result);
            list.sort(Comparator.comparing(UserCouponVo::getUnUsableMsg));
            List<Map<String, Object>> maps = Lists.newArrayList();
            for (UserCouponVo e : list) {
                Map<String, Object> map = new HashMap();
                map.put("id", e.getDisId());  //流水号
                map.put("discount", e.getDisNum()); //折扣值
                map.put("name", e.getDisName());  //优惠券名称
                map.put("limitDay", e.getEndTime()); //使用截至时间
                map.put("limitTime", e.getLimitTime());//是否限时使用:00限时,01永久有效
                map.put("minAmount", e.getMinAmount());  //起用金额(单位：分)
                map.put("maxAmount", e.getMaxAmount());  //最高优惠金额(单位：分)
                map.put("disType", e.getDisType()); //优惠类型:00满减,01折扣
                map.put("unUsableMsg", e.getUnUsableMsg()); //优惠券不可用原因
                maps.add(map);
            }
            result.setList(maps);
        } catch (ApiException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 根据用户Id查询会员看下信息
     *
     * @param userId
     * @return 会员卡信息
     */
    @Override
    public CardInfoVo getCardInfoByUserId(String userId, String cardId) {
        CardInfoVo cardInfoVo = null;
        if (StringUtils.isBlank(cardId)) {
            cardInfoVo = couponService.getCardInfoByUserId(Integer.valueOf(userId));
        } else {
            cardInfoVo = couponService.getCardInfoByCardId(cardId);
        }
        return cardInfoVo;
    }

    @Override
    public void transferCoupons(TransferCouponsRequest transferCouponsRequest) {

        Integer shopId = transferCouponsRequest.getShopId();
        String couponsId = transferCouponsRequest.getDisId();
        Integer fromUserId = transferCouponsRequest.getUserId();
        UserCouponVo coupons = couponService.getUserCouponByDisId(fromUserId, couponsId);
        if (coupons == null) {
            throw new ApiException(ErrorCodeEnum.CP6002.code(), String.format(ErrorCodeEnum.CP6002.msg(), "优惠券"));
        }
        if (!CouponConstants.COUPON_STATUS_AVL.equals(coupons.getDisSt())) {
            throw new ApiException(ErrorCodeEnum.CP6006);
        }
        UserEntity userEntity = userService.getUserByMobile(transferCouponsRequest.getMobile(), shopId);
        if (userEntity == null) {
            throw new ApiException(TK2001);
        }
        couponService.updateUserId(Long.valueOf(userEntity.getUserId()), couponsId);
        // 赠送的优惠券被领取后推送小程序消息
        MpPushRequest mpPushRequest = new MpPushRequest();
        mpPushRequest.setMessage("您的优惠券已被好友领取！");
        mpPushRequest.setShopId(shopId);
        mpPushRequest.setUserIds(Lists.newArrayList(fromUserId));
        mpPushRequest.setIndexPageId(CouponConstants.MSG_SHOW_PAGE_INDEX);
        wechatService.pushMpMsg(mpPushRequest);
    }

    @Override
    public void transferCoupons2(TransferCouponsRequest transferCouponsRequest) {

        Integer shopId = transferCouponsRequest.getShopId();
        String couponsId = transferCouponsRequest.getDisId();
        Integer fromUserId = transferCouponsRequest.getUserId();

        UserCouponVo coupons = couponService.getUserCouponByDisId(fromUserId, couponsId);
        if (coupons == null) {
            throw new ApiException(ErrorCodeEnum.CP6002.code(), String.format(ErrorCodeEnum.CP6002.msg(), "优惠券"));
        }
        if (!CouponConstants.COUPON_STATUS_AVL.equals(coupons.getDisSt())) {
            throw new ApiException(ErrorCodeEnum.CP6006);
        }
        UserEntity userEntity = userService.getUserByMobile(transferCouponsRequest.getMobile(), shopId);
        if (userEntity == null) {
            throw new ApiException(TK2001);
        }
        //此处逻辑：用户领取优惠券后，若其无上级，则赠送优惠券用户绑定为该用户上级
        //赠送用户id为 fromUserId

        GiveCouponEntity giveCouponEntity = giveCouponMapper.getCouponByDisId(couponsId);
        if (giveCouponEntity == null){
            giveCouponEntity = new GiveCouponEntity();
            giveCouponEntity.setCouponId(couponsId);//优惠券id
            giveCouponEntity.setGiveUserId(transferCouponsRequest.getUserId());//赠送人用户id
            giveCouponEntity.setShopId(transferCouponsRequest.getShopId());//商户id
            giveCouponEntity.setUserId(userEntity.getUserId());//领取人用户id
            giveCouponMapper.saveCouponOfgive(giveCouponEntity);
            couponService.updateUserId(Long.valueOf(userEntity.getUserId()), couponsId);
            // 赠送的优惠券被领取后推送小程序消息
            MpPushRequest mpPushRequest = new MpPushRequest();
            mpPushRequest.setMessage("您的优惠券已被好友领取！");
            mpPushRequest.setShopId(shopId);
            mpPushRequest.setUserIds(Lists.newArrayList(fromUserId));
            mpPushRequest.setIndexPageId(CouponConstants.MSG_SHOW_PAGE_INDEX);
            wechatService.pushMpMsg(mpPushRequest);

        }else{
            if (giveCouponEntity.getUserId() != null){
                throw new ApiException(ErrorCodeEnum.CP6001.code(), String.format(ErrorCodeEnum.CP6001.msg(), "优惠券"));
            }
        }

    }

    /**
     * 根据userId获取指定优惠券信息
     *
     * @param userId
     * @param disId
     * @return
     */
    @Override
    public UserCouponVo getUserCouponByDisId(Integer userId, String disId) {
        return couponService.getUserCouponByDisId(userId, disId);
    }

    /**
     * 获取资金账户信息
     *
     * @param userId
     * @param shopId
     * @return
     */
    // @Override
    // public FundsAccountVo getFundsAccountByUserId(String userId, String shopId) {
    //     FundsAccountVo vo = new FundsAccountVo();
    //     Long accountId = getFirstAccountId(userId).getAccountId();
    //     Account account = accountService.getAccountByAccountId(accountId);
    //     CardInfoVo cardInfoVo = couponService.getCardInfoByUserId(Integer.valueOf(userId));
    //     vo.setAmount(null == account ? 0 : account.getBalance());
    //     if (null != cardInfoVo) {
    //         vo.setCardDisNum(null);
    //         vo.setCardName(cardInfoVo.getCardName());
    //         vo.setCardId(cardInfoVo.getCardId());
    //     }
    //     vo.setVoucherNum(0);
    //     //couponService.getUserCouponList();
    //     return vo;
    // }

    /**
     * 根据userId获取指定优惠券信息
     *
     * @param userId
     * @param thirdId
     * @return
     */
    @Override
    public ChargeBill getByThirdId(String userId, String thirdId) {
        return getChargeBillByThirdSn(thirdId);
    }

    /**
     * 根据userId和id获取交易信息
     * *
     *
     * @param userId
     * @param sn
     * @return
     */
    @Override
    public ChargeBill getBySn(String userId, String sn) {
        ChargeBill chargeBill = new ChargeBill();
        chargeBill.setSn(sn);
        Page<ChargeBill> billPage = chargeBillService.getChargeBillByCondition(chargeBill, 0, 1);
        if (null == billPage) {
            return null;
        }
        return billPage.get(0);
    }
}
